﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Practices.Prism.Modularity;

namespace UltimateNavigationFramework.Loaders
{
    public class UltimateModuleRegistrationService : IUltimateModuleRegistrationService
    {
        #region Private members
        private readonly IModuleCatalog _moduleCatalog;
        private readonly Dictionary<string, ModuleInfo> _loadedModuleNames = new Dictionary<string, ModuleInfo>(); 
        #endregion

        #region Constructor
        public UltimateModuleRegistrationService(IModuleCatalog moduleCatalog)
        {
            this._moduleCatalog = moduleCatalog;
        } 
        #endregion

        #region Module Is Loaded
        public bool ModuleIsLoaded(string moduleName)
        {
            var realModule = this.GetRealModuleInfo(moduleName);

            return this._moduleCatalog.Modules.Any(
                p => p.ModuleName == realModule.ModuleName && p.State == ModuleState.Initialized);
        } 
        #endregion

        #region Register Module Info
        public void RegisterModuleInfo(string urlFriendlyModuleName, ModuleInfo realModuleObject)
        {
            if (this._loadedModuleNames.ContainsKey(urlFriendlyModuleName))
            {
                if (realModuleObject.ModuleName.ToLower() != this._loadedModuleNames[urlFriendlyModuleName].ModuleName.ToLower())
                    throw new InvalidOperationException(
                        string.Format("You cannot register UrlFriendlyModule name {0} twice with different real module names {1} and {2}.",
                            urlFriendlyModuleName, realModuleObject.ModuleName, this._loadedModuleNames[urlFriendlyModuleName]));
            }
            else
            {
                this._loadedModuleNames.Add(urlFriendlyModuleName, realModuleObject);
            }
        }  
        #endregion          

        #region Get Real Module Name
        public ModuleInfo GetRealModuleInfo(string urlFriendlyModuleName)
        {
            // first if user registered this urlfriendlymodule name and if so use it to get full name of module
            var registeredModuleName = this._loadedModuleNames.Keys
                .Where(p => p.ToLower() == urlFriendlyModuleName.ToLower()).FirstOrDefault();

            if (registeredModuleName != null)
            {
                return this._loadedModuleNames[registeredModuleName];
            }

            // now lets see if we have module with this name registered in our ModuleCatalog
            var moduleInCatalog = this.GetModuleInfoFromModuleCatalog(urlFriendlyModuleName);
            if (moduleInCatalog != null)
            {
                // lets register this name so its cached for future use
                this.RegisterModuleInfo(urlFriendlyModuleName, moduleInCatalog);
                return moduleInCatalog;
            }

            throw new Exception(string.Format("Could not find a way to identify module with name {0}",
                                              urlFriendlyModuleName));
        } 
        #endregion

        #region Get Module Info From Catalog
        private ModuleInfo GetModuleInfoFromModuleCatalog(string moduleName)
        {
            return this._moduleCatalog.Modules.Where(p => p.ModuleName.ToLower() == moduleName.ToLower()).
                    FirstOrDefault();
        }
        #endregion
    }
}
